-
Notifications
You must be signed in to change notification settings - Fork 751
feat(amazonq): Adding openDiff and acceptDiff UX to the agentic chat. #6846
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
|
Can you please update the title to be more specific to this change? |
| if (!this.onChatAnswerUpdated || !['accept-code-diff', 'reject-code-diff'].includes(action.id)) { | ||
| return | ||
| } | ||
| const answer: ChatItem = { | ||
| type: ChatItemType.ANSWER, | ||
| messageId: messageId, | ||
| buttons: [], | ||
| } | ||
| switch (action.id) { | ||
| case 'accept-code-diff': | ||
| answer.buttons = [ | ||
| { | ||
| keepCardAfterClick: true, | ||
| text: 'Accepted code', | ||
| id: 'accepted-code-diff', | ||
| status: 'success', | ||
| position: 'outside', | ||
| disabled: true, | ||
| }, | ||
| ] | ||
| break | ||
| case 'reject-code-diff': | ||
| answer.buttons = [ | ||
| { | ||
| keepCardAfterClick: true, | ||
| text: 'Rejected code', | ||
| id: 'rejected-code-diff', | ||
| status: 'error', | ||
| position: 'outside', | ||
| disabled: true, | ||
| }, | ||
| ] | ||
| break | ||
| default: | ||
| break | ||
| } | ||
| this.onChatAnswerUpdated(tabId, answer) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like this shouldn't live in this function. Is there somewhere else we can move this to?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is existing way how the buttons work/setup in both VSC and JB.
We can create a function and return answer but basically the functionality does not change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But this logic is specific to diffs which I don't think belongs here. Why not create a separate diff clicked handler? I see we already have some custom logic in
| if (action.id === `open-settings`) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logic is not specific to diff's we can extend this to feedback button and even for Confirm button!
Here we show a UX to disable the button once user click on this button.
| fileTreeTitle: '', | ||
| filePaths: item.contextList.map((file) => file.relativeFilePath), | ||
| rootFolderTitle: 'Context', | ||
| rootFolderTitle: item.title, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe fallback to ?? 'Context'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Context is not a generic text across Q so, I feel this should be either undefined or we can supply proper text as part of title which we do in our changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it, the reason I'm suggesting this is because this code is shared with all agents. So unless we are sure that we always pass "Context" in the title for all messages everywhere, there might be a UI regression.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it, right now only Q chat uses Context or contextList in project falcon but going forward we need to pass title from the agent controller.ts instead of static text.
| onFileClick = (tabID: string, filePath: string, messageId?: string) => { | ||
| this.sendMessageToExtension({ | ||
| command: 'file-click', | ||
| command: messageId === '' ? 'file-click' : 'open-diff', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels a bit hacky. Can there be a separate onOpenDiff handler?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There used to be onOpenDiff function previously but this got deprecated
@deprecated since version 4.6.3. Will be dropped after version 5.x.x. Use {@link onFileClick} instead
So Right now if user click on any file within fileTreeDiff Mynah sends event through onFileClick.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to think about this more. It's not clear to me why if messageId is empty that it should be file-click and not open-diff
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
|
||
| onCustomFormAction( | ||
| tabId: string, | ||
| messageId: string, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should it be string | undefined? Then you don't need to fallback to ''
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This wont be undefined and this is for onCustomFormAction not for onFileClick. Can you elaborate more on this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I didn't understand, aren't you passing in an empty string in connector.ts?
this.cwChatConnector.onCustomFormAction(tabId, messageId ?? '', action)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ohh I got it,
I am passing '' as part of messageId because of this code
I tested passing undefined and got undesirable result. So, I am passing ''
I remember testing this for RIV for /test too but I will give a shot once again after UX integration.
| } | ||
| } | ||
|
|
||
| export interface FileList { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we use the type from ChatItemContent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah actually we can use ChatItemContent['fileList']
| if (filePath) { | ||
| this._listOfReadFiles.push(filePath) | ||
| } else { | ||
| this._listOfReadFiles = [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does this reset the list? Looks like it would behave unexpectedly if I just look at the name of the function and not the implementation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If user tries to ask any other question in between generation or if user gets any error we need to reset to files read
To show proper UX of
2 files read, reading Sample.java
3 files read, reading foo.java
etc..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure but that shouldn't happen here. Someone reading the code in the future is not going to know why it's being reset
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me write a separate method(clearListOfReadFiles()) to reset the files.
| public get listOfReadFiles(): string[] { | ||
| return this._listOfReadFiles | ||
| } | ||
| public get getFilePath(): string | undefined { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is already a getter function, get in the name is redundant
| public get getFilePath(): string | undefined { | |
| public get filePath(): string | undefined { |
|
|
||
| export class ChatSession { | ||
| private sessionId?: string | ||
| private _listOfReadFiles: string[] = [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
list is redundant
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Required for the Reading files UX which still a TODO. I can revisit on this once we have final UX into place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant that the variable name can just be _readFiles
| private _listOfReadFiles: string[] = [] | ||
| private _filePath: string | undefined | ||
| private _tempFilePath: string | undefined |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please check the naming or add some documentation, it's very unclear what these are used for
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will add some comments on top of this variable. There might be some duplication due to lot of dependencies on our PR's.
I will add a TODO to revisit and remove necessary variables if required.
| this.sessionId = id | ||
| } | ||
| public get listOfReadFiles(): string[] { | ||
| return this._listOfReadFiles |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually I think we can get this information from chatHistory?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please can you point me the code where this was implemented? I checked the latest PR and looks like its still TODO
| public setSessionID(id?: string) { | ||
| this.sessionId = id | ||
| } | ||
| public get listOfReadFiles(): string[] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| public get listOfReadFiles(): string[] { | |
| public get readFiles(): string[] { |
mr-lee
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approved to unblock.
| const fileExists = await fs.existsFile(filePath) | ||
| // Check if fileExists=false, If yes, return instead of showing broken diff experience. | ||
| if (!session.tempFilePath) { | ||
| return | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does this notify the user?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No It wont notify the user for now, but good to have a Information notification message. I will add this to the TODO.
| export class ChatSession { | ||
| private sessionId?: string | ||
| /** | ||
| * _listOfReadFiles = list of files read from the project to gather context before generating response. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do you need to pass this around?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To count # of files read as per UX requirement.

Problem
Solution
QChatPOCFileWrite.mov
TODO:
feature/xbranches will not be squash-merged at release time.